using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;
using XnaDevRu.ContentBuilder.Framework;

namespace XnaDevRu.ContentBuilder
{
    public partial class MainForm : Form
    {
        private ContentProject _project = new ContentProject();
        private string _openedProject = "";
        private string registrySubKey = @"Software\XNADev.ru\ContentBuilder";

        public MainForm()
        {
            InitializeComponent();

            UpdateTitle();
			propertyContent.SelectedObject = _project.ProjectOptions;
            _project.RegisterLogger(new TextBoxLogger(outputText));

			testFileAssociation();

			// CHP - load the last-used project file
			Microsoft.Win32.RegistryKey regKey;
			regKey = Registry.CurrentUser.OpenSubKey(registrySubKey, true);
			if (regKey != null)
			{
				string lastproj = regKey.GetValue("projfile").ToString();
				if (File.Exists(lastproj))
				{
					OpenProjectFile(lastproj);
				}
			}
			else
			{
				Registry.CurrentUser.CreateSubKey(registrySubKey);
			}
			Registry.CurrentUser.Close();
        }

		public MainForm(string fileName)
		{
			InitializeComponent();

			try
			{
				OpenProject(fileName);
			}
			catch
			{
				_project = new ContentProject();
				_openedProject = "";
				UpdateTitle();
				propertyContent.SelectedObject = _project.ProjectOptions;
				_project.RegisterLogger(new TextBoxLogger(outputText));
			}

			testFileAssociation();
		}

        private object InitContent(string fileName)
        {
            return _project.InitContentFile(fileName);
        }

        private void RemoveContent(object content)
        {
            listContent.Items.Remove(content);
            _project.ContentFiles.Remove(content as ContentFile);
        }

		// CHP - added to remove pipelines like content was already being removed
		private void RemovePipeline(object pipeline)
		{
			listPipelines.Items.Remove(pipeline);
			_project.ContentAssemblies.RemoveAssembly(pipeline as string);
		}

		private void OpenProject(string fileName)
		{
			listContent.Items.Clear();
			listPipelines.Items.Clear();

			_openedProject = fileName;
			_project = new ContentProject();
			_project.RegisterLogger(new TextBoxLogger(outputText));
			_project.Load(_openedProject);
			UpdateTitle();
			foreach (ContentFile content in _project.ContentFiles)
			{
				listContent.Items.Add(content);
			}
			foreach (string s in _project.ContentAssemblies.Assemblies)
			{
				if (!PipelineAssemblyManager.IsDefaultAssembly(s))
					listPipelines.Items.Add(s);
			}
		}

        private void addContentButton_Click(object sender, EventArgs e)
        {
            openFileDialog.DefaultExt = "*.*";
            openFileDialog.Filter = _project.ContentExtensionsFilter;
            openFileDialog.FilterIndex = 0;
            openFileDialog.Multiselect = true;
            openFileDialog.Title = "Open content...";

            if (openFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                for (int i = 0; i < openFileDialog.FileNames.Length; i++)
                {
                    listContent.Items.Add(InitContent(openFileDialog.FileNames[i]));
                }
            }
        }

        private void listContent_SelectedIndexChanged(object sender, EventArgs e)
        {
            propertyContent.SelectedObject = listContent.SelectedItem;
        }

        // CHP - updated to remove all selected content
        private void removeContentButton_Click(object sender, EventArgs e)
        {
            List<Object> selectedList = new List<object>();
            foreach (Object obj in listContent.SelectedItems)
            {
                selectedList.Add(obj);
            }

            foreach(Object obj in selectedList)
            {
                RemoveContent(obj);
            }

            selectedList.Clear();
        }

        private void addPipelineButton_Click(object sender, EventArgs e)
        {
            openFileDialog.DefaultExt = "*.dll";
            openFileDialog.Filter = "Assemblies (*.dll)|*.dll|Executables (*.exe)|*.exe|All files (*.*)|*.*";
            openFileDialog.Multiselect = true;
            openFileDialog.Title = "Open content pipeline assembly...";

            if (openFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                for (int i = 0; i < openFileDialog.FileNames.Length; i++)
                {
                    AddPipelineFile(openFileDialog.FileNames[i]);
                }
            }
        }

        // CHP - updated to remove all selected pipelines
        private void removePipelineButton_Click(object sender, EventArgs e)
        {
            List<Object> selectedList = new List<object>();
            foreach (Object obj in listPipelines.SelectedItems)
            {
                selectedList.Add(obj);
            }

            foreach (Object obj in selectedList)
            {
                RemovePipeline(obj);
            }

            selectedList.Clear();
        }

        private void BuildToolStripButton_Click(object sender, EventArgs e)
        {
            _project.Build(true);
        }

        private void UpdateTitle()
        {
            if (_openedProject.Length != 0)
            {
                Text = "XNA Content Builder - (" + _openedProject + ")";
            }
            else
            {
                Text = "XNA Content Builder - (Unitled.xcbproj)";
            }
        }

        private void Save(string fileName)
        {
            _project.Save(fileName);
            _openedProject = fileName;
        }

        private void outputText_TextChanged(object sender, EventArgs e)
        {
            lock (outputText)
            {
                outputText.SelectionStart = outputText.TextLength;
                outputText.SelectionLength = 0;
                outputText.ScrollToCaret();
            }
        }

        private void saveToolStripSplitButton_ButtonClick(object sender, EventArgs e)
        {
            if (_openedProject.Length != 0)
            {
                Save(_openedProject);
            }
            else
            {
                if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
                {
                    Save(saveFileDialog.FileName);
                }
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveToolStripSplitButton_ButtonClick(sender, e);
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                _openedProject = saveFileDialog.FileName;
                Save(_openedProject);
                UpdateTitle();
            }
        }

        private void newToolStripButton_Click(object sender, EventArgs e)
        {
            listContent.Items.Clear();
            listPipelines.Items.Clear();

            _openedProject = "";
            _project = new ContentProject();
            _project.RegisterLogger(new TextBoxLogger(outputText));
            UpdateTitle();
            // CHP - force the properties window to update when loading settings
            UpdatePropertiesWindow();
        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            openFileDialog.DefaultExt = "*.xcbproj";
            openFileDialog.Filter = "XCB Project files (*.xcbproj)|*.xcbproj|All files (*.*)|*.*";
            openFileDialog.Multiselect = false;
            openFileDialog.Title = "Open project...";

            if (openFileDialog.ShowDialog(this) == DialogResult.OK)
                OpenProjectFile(openFileDialog.FileName);
        }

		// CHP - added to allow drag-n-drop project file loading
		private void OpenProjectFile(string filename)
		{
			listContent.Items.Clear();
			listPipelines.Items.Clear();

			_openedProject = filename;
			_project = new ContentProject();
			_project.RegisterLogger(new TextBoxLogger(outputText));
			_project.Load(_openedProject);
			UpdateTitle();
			foreach (ContentFile content in _project.ContentFiles)
			{
				listContent.Items.Add(content);
			}
			foreach (string s in _project.ContentAssemblies.Assemblies)
			{
				listPipelines.Items.Add(s);
			}

			// CHP - force the properties window to update when loading settings
			UpdatePropertiesWindow();
		}

		private void optionsToolStripButton_Click(object sender, EventArgs e)
		{
			UpdatePropertiesWindow();
		}

		private void testFileAssociation()
		{
			try
			{
				RegistryKey root = Registry.ClassesRoot;

				string[] subkeys = root.GetSubKeyNames();
				foreach (string s in subkeys)
					if (s == ".xcbproj" && root.OpenSubKey(".xcbproj").GetValue("", "").ToString() == "XnaContentBuilder"
						&& root.OpenSubKey(@"XnaContentBuilder\shell\Open\command").GetValue("", "").ToString() == Application.ExecutablePath + " \"%1\"")
						return;

				if (MessageBox.Show(this, @"XNA Content Builder is not your default program to open .xcbproj files.
Do you want to make it default?", "XNA Content Builder", MessageBoxButtons.YesNo, MessageBoxIcon.None) == DialogResult.Yes)
				{
					RegistryKey xcb = root.CreateSubKey(".xcbproj");
					xcb.SetValue("", "XnaContentBuilder");

					RegistryKey xcbexe = root.CreateSubKey("XnaContentBuilder");
					RegistryKey command = xcbexe.CreateSubKey(@"shell\Open\command");
					command.SetValue("", Application.ExecutablePath + " \"%1\"");

					RegistryKey icon = xcbexe.CreateSubKey("DefaultIcon");
					icon.SetValue("", Environment.CurrentDirectory + "\\xcb.ico");

					root.Flush();
				}
			}
			catch { }
		}

		// CHP - force the properties window to update when loading settings
		private void UpdatePropertiesWindow()
		{
			propertyContent.SelectedObject = _project.ProjectOptions;
		}

		#region Drag&Drop from zygote
		private void listContent_DragDrop(object sender, DragEventArgs e)
		{
			string[] files = (string[])e.Data.GetData("FileDrop");

			for (int x = 0; x < files.Length; x++)
			{
				if (File.Exists(files[x]))
					AddContentFile(files[x]);
				else if (Directory.Exists(files[x]))
				{
					AddDirectory(files[x]);
				}
			}
		}

		private void listContent_DragEnter(object sender, DragEventArgs e)
		{
			if (e.Data.GetDataPresent("FileDrop"))
				e.Effect = DragDropEffects.Copy;
		}

		private void AddContentFile(string fileName)
		{
			listContent.Items.Add(InitContent(fileName));
		}

        private void AddDirectory(string directory)
        {
            string[] files = Directory.GetFiles(directory);
            string[] dirs = Directory.GetDirectories(directory);

            for (int x = 0; x < files.Length; x++)
            {
                if (File.Exists(files[x]))
                {
                    AddContentFile(files[x]);
                }
            }

            for (int x = 0; x < dirs.Length; x++)
            {
                if (Directory.Exists(dirs[x]))
                {
                    AddDirectory(dirs[x]);
                }
            }
        }

        // CHP - added the ability to press the delete key with content highlighted and remove all highlighted
        private void listContent_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                removeContentButton_Click(sender, EventArgs.Empty);
            }
        }

        // CHP - added the ability to press the delete key with pipelines highlighted and remove all highlighted
        private void listPipelines_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                removePipelineButton_Click(sender, EventArgs.Empty);
            }
        }

        // CHP - added to facilitate adding new pipelines from multiple functions
        private void AddPipelineFile(string fileName)
        {
            _project.ContentAssemblies.AddAssembly(fileName);
            listPipelines.Items.Add(fileName);
        }

        // CHP - recursive function to add pipeline files from directories (not that you should...)
        private void AddPipelineDirectory(string directory)
        {
            string[] files = Directory.GetFiles(directory);
            string[] dirs = Directory.GetDirectories(directory);

            for (int x = 0; x < files.Length; x++)
            {
                if (File.Exists(files[x]))
                {
                    AddPipelineFile(files[x]);
                }
            }

            for (int x = 0; x < dirs.Length; x++)
            {
                if (Directory.Exists(dirs[x]))
                {
                    AddPipelineDirectory(dirs[x]);
                }
            }
        }

        // CHP - Drop event for adding a new pipeline to the list (looks similar to the above function, i know...probably should be combined somehow)
        private void listPipelines_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = (string[])e.Data.GetData("FileDrop");

            for (int x = 0; x < files.Length; x++)
            {
                if (File.Exists(files[x]))
                {
                    AddPipelineFile(files[x]);
                }
                else if (Directory.Exists(files[x]))
                {
                    AddPipelineDirectory(files[x]);
                }
            }
        }

        // CHP - generic function to cover all objects' DragEnter since they're all the same anyway
        private void GenericDragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent("FileDrop"))
            {
                e.Effect = DragDropEffects.Copy;
            }
        }

        // CHP - allows opening of a project file by dragging it onto the main form
        private void MainForm_DragDrop(object sender, DragEventArgs e)
        {
            OpenProjectFile(((string[])e.Data.GetData("FileDrop"))[0]);
		}
		#endregion

        private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
        {

        }
	}
}